home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / xlib / skeeter.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  24KB  |  1,015 lines

  1. /*
  2.  * Copyright (c) 1993-94, Silicon Graphics, Inc.
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that the name of Silicon Graphics may not be used in any advertising or
  7.  * publicity relating to the software without the specific, prior written
  8.  * permission of Silicon Graphics.
  9.  *
  10.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  11.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  12.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  13.  *
  14.  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  15.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE
  17.  * POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  *
  20.  * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
  21.  */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <math.h>
  25. #include <string.h>
  26. #include <GL/gl.h>
  27. #include <GL/glu.h>
  28. #include <GL/glx.h>
  29. #include <X11/Xlib.h>
  30. #include <X11/Xutil.h>
  31. #include <X11/keysym.h>
  32. #include <X11/cursorfont.h>
  33.  
  34. #include "skeeter.h"
  35.  
  36. /*
  37.  * attribute list for an RGB double buffered visual, with
  38.  * red, green, blue, and depth components
  39.  */
  40. static int attributeList[] = {GLX_RGBA, GLX_DOUBLEBUFFER, 
  41.     GLX_RED_SIZE, 1,
  42.     GLX_GREEN_SIZE, 1,
  43.     GLX_BLUE_SIZE, 1,
  44.     GLX_DEPTH_SIZE, 1,
  45.     None };
  46.  
  47. int REDRAW = True;
  48. /*
  49.  * overlay plane visual attribute list
  50.  */
  51. static int al2[] = {GLX_LEVEL, 2,  None };
  52.  
  53. /*
  54.  * popup plane visual attribute list
  55.  */
  56. static int al1[] = {GLX_LEVEL, 1,  None };
  57.  
  58.  
  59. /*
  60.  * function to wait for a window to map
  61.  */
  62. static Bool WaitForNotify (Display *d, XEvent *e, char *arg)
  63. {
  64.     return (e->type == MapNotify) && (e->xmap.window == (Window) arg);
  65. }
  66.  
  67.  
  68. /*
  69.  * functions in this file
  70.  */
  71. void drawScene(void);
  72. void updateFlightParams(void);
  73. void pull(void);
  74. void drawCD(GLUquadricObj *);
  75. void gluErrorHandler(void);
  76. void makeCD(void);
  77. void drawBackground(void);
  78. void makeSkeeter(void);
  79. void initStruct(void);
  80. void newParams(int);
  81. void parseArgs(int, char **);
  82. void drawSkeeter(int, int, int, int);
  83.  
  84.  
  85.  
  86. main(int argc, char **argv)
  87. {
  88.  
  89.     XVisualInfo *vi;              /* X Visual  */
  90.     XVisualInfo *ovi;              /* X Visual  */
  91.  
  92.     Colormap cmap, ocmap;         /* X Colormap */
  93.     XSetWindowAttributes swa;     /* X Window Attributes */
  94.     XEvent event;                 /* X event             */
  95.     Window root_win;
  96.     char    xlat[20];
  97.     int     nchar = 20;
  98.     KeySym  key;
  99.     XComposeStatus cs;
  100.     XWindowAttributes winattrs;
  101.     
  102.     XColor  spix, pixel;
  103.     float fx, fy;
  104.     int num;
  105.     XMotionEvent  *motion;
  106.     XButtonEvent  *button;
  107.     static char cur[] = {0x0f, 0x0f};
  108.     XColor color;
  109.     Pixmap source;
  110.     int looper, now;
  111.  
  112.  
  113.     if (argc >1)
  114.         parseArgs(argc, argv);
  115.  
  116.     dpy = XOpenDisplay (0);
  117.     XSynchronize(dpy, True);
  118.  
  119.   /* 
  120.    * get a regular, double buffer, rgb visual 
  121.    * if we can't get it, big trouble, so bail out!
  122.    */
  123.     vi = glXChooseVisual (dpy, DefaultScreen(dpy), attributeList);
  124.     if (vi == NULL) {
  125.         printf("\n can't get requested visual type, bye...\n");
  126.         exit(0);
  127.         }
  128.  
  129.    /* 
  130.     * create a GLX context
  131.     */
  132.     cx = glXCreateContext (dpy, vi, None, GL_TRUE);
  133.  
  134.    /* 
  135.     * create a colormap using this visual 
  136.     */
  137.     cmap = XCreateColormap (dpy, RootWindow(dpy, vi->screen), vi->visual,
  138.                             AllocNone);
  139.  
  140.   /* 
  141.    *create an X Window 
  142.    */
  143.     swa.colormap = cmap;
  144.     swa.border_pixel = 1;
  145.     swa.event_mask = StructureNotifyMask;
  146.  
  147.     source = XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy),
  148.                                          cur, 1, 1, 0, 0, 1);
  149.     swa.cursor = XCreatePixmapCursor(dpy, source, source,
  150.                                         &color, &color, 0, 0);
  151.  
  152.     win = XCreateWindow (dpy, RootWindow(dpy,vi->screen), 
  153.                          0, 0, WINSIZE, WINSIZE,
  154.                          0, vi->depth, InputOutput, vi->visual,
  155.                          CWCursor | CWBorderPixel | 
  156.                          CWColormap|CWEventMask, &swa);
  157.  
  158.  
  159.     XMapWindow (dpy,win);
  160.  
  161.    /*
  162.     * wait for window to map so that we can start drawing into
  163.     * it.
  164.     */
  165.     XIfEvent(dpy, &event, WaitForNotify, (char *) win);
  166.  
  167.   /*
  168.    * now try to create an overlay window 
  169.    * the scheme is as follows:
  170.    *       - first try to get a level 2 visual, one in the overlay planes.
  171.    *      if that fails...
  172.    *    - try to get a level 1 visual, one in the popup planes.  
  173.    *      if that fails, just do all drawing in the normal planes
  174.    */
  175.  
  176.     ovi = glXChooseVisual (dpy, DefaultScreen(dpy), al2);
  177.  
  178.     if (ovi == NULL) {
  179.         printf("\n can't get requested overlay visual type...\n");
  180.         ovi = glXChooseVisual (dpy, DefaultScreen(dpy), al1);
  181.         if (ovi)
  182.             fprintf(stderr, "got popup plane window!\n");
  183.         }
  184.     else
  185.        fprintf(stderr, "got overlay plane window!\n");
  186.  
  187.     if (ovi == NULL) {
  188.         printf("\n can't get popup visual either, using regular visual...\n");
  189.         }
  190.  
  191.     if (ovi) {
  192.         USE_OVERLAY = True;
  193.        /* 
  194.         * we have an overlay visual, so 
  195.         * create a GLX context, along with the rest of the junk
  196.         * we need to create a window with this viusal
  197.         */
  198.         ocx = glXCreateContext (dpy, ovi, None, GL_TRUE);
  199.  
  200.        /* create a colormap using this visual */
  201.         ocmap = XCreateColormap (dpy, RootWindow(dpy, ovi->screen), ovi->visual,
  202.                                 AllocNone);
  203.  
  204.        /* create a X Window */
  205.         swa.colormap = ocmap;
  206.         swa.border_pixel = 0;
  207.         swa.win_gravity = UnmapGravity;
  208.         swa.bit_gravity = NorthWestGravity;
  209.         swa.background_pixel = BlackPixel(dpy, ovi->screen);
  210.  
  211.         owin = XCreateWindow (dpy, win, 0, 0, WINSIZE, WINSIZE,
  212.                              0, ovi->depth, InputOutput, ovi->visual,
  213.                              CWBorderPixel|CWColormap|CWEventMask, &swa);
  214.     
  215.  
  216.         XMapWindow (dpy,owin);
  217.  
  218.         }
  219.  
  220.     /* install the colormap windows property so that overlay colormap
  221.      * takes hold when we move cursor into window
  222.      */
  223.      
  224.      winList[0] = win;
  225.      winList[1] = owin;
  226.      
  227.      if (USE_OVERLAY) {
  228.          winList[1] = owin;
  229.          num = 2;
  230.          }
  231.      else
  232.          num = 1; 
  233.  
  234.     XSetWMColormapWindows(dpy, win, winList, num);
  235.  
  236.  /*
  237.   * get the 'white' pixel value, we will need this
  238.   * to set colormap index for overlay drawing
  239.   */
  240.  
  241.     if (USE_OVERLAY) {
  242.         XAllocNamedColor(dpy, ocmap, "white", &spix, &pixel);
  243.         WHITE_PIXEL_NUM = pixel.pixel;
  244.         XAllocNamedColor(dpy, ocmap, "RED", &spix, &pixel);
  245.         RED_PIXEL_NUM = pixel.pixel;
  246.         XAllocNamedColor(dpy, ocmap, "GRAY", &spix, &pixel);
  247.         BLACK_PIXEL_NUM = pixel.pixel;
  248.         }
  249.  
  250.   /* connect the context to the window */
  251.     if (!glXMakeCurrent(dpy, win, cx) == GL_TRUE) {
  252.         return 0;
  253.     }
  254.  
  255.  
  256.  
  257.  /*
  258.   * get the window size and location so that we can
  259.   * make the cylinder track the mouse movements *somewhat* acurately
  260.   */
  261.  
  262.     XGetWindowAttributes(dpy, win, &winattrs);
  263.     xorigin = winattrs.x;
  264.     yorigin = winattrs.y;
  265.     width = winattrs.width;
  266.     height = winattrs.height;
  267.  
  268.  /*
  269.   * starting location of skeeter, my choice
  270.   */
  271.     xloc = 100;
  272.     yloc = 100;
  273.  
  274.   /*
  275.    * finally, some OpenGL stuff!!
  276.    * set up zbuffer depth test, projection & model matrices, light models,
  277.    * and don't forget to turn on the light!
  278.    */
  279.    glViewport(0, 0, width, height);
  280.    glEnable(GL_DEPTH_TEST);
  281.    glDepthFunc(GL_LEQUAL);
  282.  
  283.  
  284.   /*
  285.    * set up projection matrix; we will use perspective projection
  286.    * and set our eye point 10 z units away, in effect, you will be
  287.    * shootin' from your chair, dead on!
  288.    */
  289.    glMatrixMode(GL_PROJECTION);
  290.    glLoadIdentity();
  291.  
  292.    gluPerspective(95.0, 1.0, 0.5, ZDEPTH);
  293.    gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
  294.  
  295.   /*
  296.    * perspective set, model matrix stuff from now on...
  297.    */
  298.    glMatrixMode(GL_MODELVIEW);
  299.  
  300.    glTranslatef(0.0, 0.0, -4.0);
  301.  
  302.   /*
  303.    * let there be light!
  304.    */
  305.    glLightfv(GL_LIGHT1, GL_POSITION, lpos);
  306.    glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
  307.    glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
  308.    glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
  309.  
  310.    glLightfv(GL_LIGHT2, GL_POSITION, l2_lpos);
  311.    glLightfv(GL_LIGHT2, GL_AMBIENT, l2_ambient);
  312.    glLightfv(GL_LIGHT2, GL_DIFFUSE, l2_diffuse);
  313.    glLightfv(GL_LIGHT2, GL_SPECULAR, l2_specular);
  314.    glLightf(GL_LIGHT2, GL_SPOT_CUTOFF, 45.0);
  315.    glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, l2_direction);
  316.    glLightf(GL_LIGHT2, GL_SPOT_EXPONENT, 80);
  317.  
  318.    glLightfv(GL_LIGHT3, GL_POSITION, lpos);
  319.    glLightfv(GL_LIGHT3, GL_POSITION, l3_lpos);
  320.    glLightfv(GL_LIGHT3, GL_AMBIENT, l3_ambient);
  321.    glLightfv(GL_LIGHT3, GL_DIFFUSE, l3_diffuse);
  322.    glLightfv(GL_LIGHT3, GL_SPECULAR, l3_specular);
  323.    glLightf(GL_LIGHT3, GL_SPOT_CUTOFF, 90.0);
  324.    glLightf(GL_LIGHT3, GL_SPOT_EXPONENT, 100);
  325.  
  326.    glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
  327.    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, alm);
  328.    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); 
  329.  
  330.    glEnable(GL_LIGHTING);
  331.  
  332.    glEnable(GL_LIGHT3);
  333.  
  334.    if (num_lights > 1)
  335.        glEnable(GL_LIGHT2);
  336.  
  337.    if (num_lights > 2)
  338.        glEnable(GL_LIGHT3);
  339.  
  340.   /*
  341.    * now set up the matrix stuff for the overlay window.
  342.    * since not much going on here as far as 3D stuff,
  343.    * just keep it simple, -1 to +1 in X and Y, no Z component
  344.    * since we don't do any depth stuff in the overlay planes 
  345.    * anyway
  346.    */
  347.    if (USE_OVERLAY) {
  348.        glXMakeCurrent(dpy, owin, ocx); 
  349.        glViewport(0, 0, width, height);
  350.        glMatrixMode(GL_PROJECTION);
  351.        glLoadIdentity();
  352.        glOrtho(-1, 1, -1, 1, 0, 0);
  353.        glMatrixMode(GL_MODELVIEW);
  354.        }
  355.  
  356.   /*
  357.    * set X input stuff
  358.    */
  359.    XSelectInput(dpy, win, ExposureMask |StructureNotifyMask |
  360.                        ButtonPressMask | Button1MotionMask |
  361.                SubstructureNotifyMask | KeyPressMask |
  362.                        KeyReleaseMask | ButtonReleaseMask );
  363.  
  364.  
  365.    if (USE_OVERLAY) 
  366.        XSelectInput(dpy, owin, ExposureMask |StructureNotifyMask |
  367.                            ButtonPressMask | Button1MotionMask |
  368.                SubstructureNotifyMask | KeyPressMask |
  369.                            KeyReleaseMask | ButtonReleaseMask );
  370.  
  371.   /*
  372.    * if we are not using overlay drawing, set the overlay drawing
  373.    * window to the main planes window
  374.    */
  375.    if (!USE_OVERLAY) {
  376.        owin = win;
  377.        ocx = cx;
  378.        }
  379.  
  380.   glXMakeCurrent(dpy, win, cx);
  381.  
  382.   glClearColor(0.0, 0.0, 0.0, 0.0);
  383.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  384.  
  385.   makeCD();
  386.  
  387.   if (DO_BACKGROUND)
  388.       drawBackground();
  389.  
  390.   glXSwapBuffers(dpy, win);
  391.  
  392.   glXMakeCurrent(dpy, owin, ocx);
  393.   makeSkeeter();
  394.  
  395.   glXMakeCurrent(dpy, win, cx);
  396.  
  397.  /*
  398.   * initialize data structures
  399.   */
  400.  
  401.   initStruct();
  402.  
  403.   /*
  404.    * the dreaded X Event loop...
  405.    */
  406.    looper = now = 0;
  407.    while (1) {
  408.  
  409.        if (XPending(dpy)) {
  410.             XNextEvent(dpy, &event);
  411.             switch (event.type) {
  412.         case Expose:
  413.  
  414.                     glXMakeCurrent(dpy, owin, ocx);
  415.                     glClearIndex(0);
  416.                     glClear(GL_COLOR_BUFFER_BIT);
  417.  
  418.                     drawScene();
  419.                     drawSkeeter(xloc, yloc, WHITE_PIXEL_NUM, True);
  420.  
  421.             break;
  422.  
  423.          case ConfigureNotify:
  424.                    {
  425.                      int newwidth, newheight;
  426.                   /*
  427.                    * get window size in case of a resize...
  428.                    */
  429.                     XGetWindowAttributes(dpy, win, &winattrs);
  430.                     xorigin = winattrs.x;
  431.                     yorigin = winattrs.y;
  432.                     width = winattrs.width;
  433.                     height = winattrs.height;
  434.  
  435.                   /*
  436.                    * clear overlay window
  437.                    */
  438.                     if (USE_OVERLAY) {
  439.                         XResizeWindow(dpy, owin, width, height);
  440.                         glXMakeCurrent(dpy, owin, ocx);
  441.                         glViewport(0, 0, width, height);
  442.                         drawSkeeter(xloc, yloc, WHITE_PIXEL_NUM, True);
  443.                         }
  444.  
  445.                     glXMakeCurrent(dpy, win, cx);
  446.                     glViewport(0, 0, width, height);
  447.                     }
  448.  
  449.                     now = True;
  450.  
  451.             break;
  452.  
  453.                 case ButtonPress:
  454.                     button = (XButtonEvent *) &event;
  455.                     drawSkeeter(button->x, button->y, RED_PIXEL_NUM, True);
  456.                     REDRAW = False;
  457.                     break;
  458.  
  459.                 case ButtonRelease:
  460.                     REDRAW = True;
  461.                     break;
  462.  
  463.  
  464.         case KeyPress:
  465.                     XLookupString((XKeyEvent *) &event, xlat, nchar, &key, &cs);
  466.  
  467.                     switch (key) {
  468.  
  469.                         case XK_Escape:
  470.                             printf("\n bye...\n");
  471.                             exit(0);
  472.                             break;
  473.  
  474.                         case XK_space:
  475.                            pull();
  476.                            break;
  477.                         }
  478.  
  479.                     break;
  480.  
  481.  
  482.         case MotionNotify:
  483.                     motion = (XMotionEvent *) &event;
  484.                     drawSkeeter(motion->x, motion->y, WHITE_PIXEL_NUM, False);
  485.                     xloc = motion->x;
  486.                     yloc = motion->y;
  487.             break;
  488.  
  489.         default:
  490.             break;
  491.  
  492.                 }
  493.  
  494.              }
  495.  
  496.              if (REDRAW) {
  497.                 updateFlightParams();
  498.                 drawScene();
  499.                 }
  500.  
  501.             }
  502.  
  503. }
  504.  
  505.  
  506.  
  507. /*
  508.  * routine to draw the SKEETER, in the overlay planes if
  509.  * available
  510.  */
  511.  
  512. GLUquadricObj  *head, *rightEye, *leftEye, *body1, *body2, *body3;
  513.  
  514. void
  515. drawSkeeter(int ix, int iy, int color, int now)
  516. {
  517.  
  518.   static int doMe = 1;
  519.   
  520.   int i; 
  521.   float x, y;
  522.   float v[2];
  523.  
  524. /*
  525.  * little slight-of-hand here.  X generates a truck load of events
  526.  * for cursor movements.  to get good performance, we will only process
  527.  * say every 10th cursor motion event, unless we are directed to do it
  528.  * 'now'.  an example of when we would want to redraw cross hair 'now'
  529.  * would be when the window is resized
  530.  *            
  531.  */
  532.  
  533.  
  534.   if (!now) {
  535.  
  536.       doMe++;
  537.       if ((doMe % 10) != 0)
  538.           return;
  539.       else
  540.           doMe = 1;
  541.       }
  542.  
  543.  
  544.  /*
  545.   *  we need to map the X window x and y coordinates to fit into
  546.   *  our overlay window space -1 to 1 in both X and Y
  547.   */
  548.   x = (float) ((((float) ix) - (((float)width)/2.0)) / (((float)width)/2.0));
  549.   y = (float) (( (((float)height)/2.0) - ((float) iy)) / (((float)height)/2.0));
  550.  
  551.  
  552.  /*
  553.   * make overlay window current and clear
  554.   */
  555.   glXMakeCurrent(dpy, owin, ocx);
  556.  
  557.  
  558.   if (USE_OVERLAY) {
  559.       glClearIndex(0);
  560.       glClear(GL_COLOR_BUFFER_BIT);
  561.       glIndexi(color);
  562.       }
  563.   else
  564.       glColor3b(1, 0, 0);
  565.  
  566.  
  567.  /*
  568.   * push down a matrix, multiply in a translation to current X and Y
  569.   * positions and call the SKEETER display list
  570.   */
  571.  
  572.   glPushMatrix();
  573.  
  574.      glTranslatef(x, y, 0.0);
  575.      glCallList(SKEETER_LIST);
  576.  
  577.   glPopMatrix();
  578.  
  579. }
  580.  
  581.  
  582. /*
  583.  * routine to make a 'skeeter display list
  584.  */
  585. void
  586. makeSkeeter()
  587. {
  588.  
  589.      glNewList(SKEETER_LIST, GL_COMPILE);
  590.  
  591.      glPushMatrix();
  592.  
  593.        glScalef(.1, .1, .0);
  594.  
  595.        if (!head)
  596.            head = gluNewQuadric();
  597.  
  598.        if (!rightEye)
  599.            rightEye = gluNewQuadric();
  600.  
  601.        if (!leftEye)
  602.            leftEye = gluNewQuadric();
  603.  
  604.        if (!body1)
  605.            body1 = gluNewQuadric();
  606.  
  607.        if (!body2)
  608.            body2 = gluNewQuadric();
  609.  
  610.        if (!body3)
  611.            body3 = gluNewQuadric();
  612.  
  613.            gluQuadricCallback(rightEye, GLU_ERROR, gluErrorHandler);
  614.            gluQuadricCallback(leftEye, GLU_ERROR, gluErrorHandler);
  615.            gluQuadricCallback(head, GLU_ERROR, gluErrorHandler);
  616.            gluQuadricCallback(body1, GLU_ERROR, gluErrorHandler);
  617.            gluQuadricCallback(body2, GLU_ERROR, gluErrorHandler);
  618.            gluQuadricCallback(body3, GLU_ERROR, gluErrorHandler);
  619.  
  620.            glIndexi(BLACK_PIXEL_NUM);
  621.  
  622.            gluDisk(head, 0.0, 0.5, 10.0, 10.0);
  623.  
  624.            glIndexi(RED_PIXEL_NUM);
  625.            glPushMatrix();
  626.                glTranslatef(-0.2, 0.4, 0.0);
  627.                gluDisk(rightEye, 0.0, 0.25, 10.0, 10.0);
  628.            glPopMatrix();
  629.  
  630.            glPushMatrix();
  631.                glTranslatef(-0.2, -0.4, 0.0);
  632.                gluDisk(leftEye, 0.0, 0.25, 10.0, 10.0);
  633.            glPopMatrix();
  634.  
  635.            glIndexi(BLACK_PIXEL_NUM);
  636.            glPushMatrix();
  637.                glTranslatef(0.5, 0.0, 0.0);
  638.                gluDisk(body1, 0.0, 0.4, 10.0, 10.0);
  639.            glPopMatrix();
  640.  
  641.            glPushMatrix();
  642.                glTranslatef(0.9, 0.0, 0.0);
  643.                gluDisk(body2, 0.0, 0.4, 10.0, 10.0);
  644.            glPopMatrix();
  645.  
  646.            glPushMatrix();
  647.                glTranslatef(1.3, 0.0, 0.0);
  648.                gluDisk(body3, 0.0, 0.4, 10.0, 10.0);
  649.            glPopMatrix();
  650.  
  651.            glBegin(GL_LINES);
  652.                 glVertex3f(0.4, 0.0, 0.0);
  653.                 glVertex3f(0.6, 1.0, 0.0);
  654.                
  655.                 glVertex3f(0.4, 0.0, 0.0);
  656.                 glVertex3f(0.6, -1.0, 0.0);
  657.  
  658.                 glVertex3f(0.9, 0.0, 0.0);
  659.                 glVertex3f(1.1, 1.0, 0.0);
  660.                
  661.                 glVertex3f(0.9, 0.0, 0.0);
  662.                 glVertex3f(1.1, -1.0, 0.0);
  663.  
  664.                 glVertex3f(1.3, 0.0, 0.0);
  665.                 glVertex3f(1.5, 1.0, 0.0);
  666.                
  667.                 glVertex3f(1.3, 0.0, 0.0);
  668.                 glVertex3f(1.5, -1.0, 0.0);
  669.            glEnd();
  670.  
  671.            glIndexi(WHITE_PIXEL_NUM);
  672.            glBegin(GL_TRIANGLES);
  673.                 glVertex3f(0.5, 0.2, 0.0);
  674.                 glVertex3f(1.0, 0.2, 0.0);
  675.                 glVertex3f(2.0, 0.9, 0.0);
  676.  
  677.                 glVertex3f(0.5, -0.2, 0.0);
  678.                 glVertex3f(1.0, -0.2, 0.0);
  679.                 glVertex3f(2.0, -0.9, 0.0);
  680.            glEnd();
  681.  
  682.      glPopMatrix();
  683.  
  684.    
  685.    glPopMatrix();
  686.  
  687.    glEndList();
  688.  
  689.  
  690. }
  691.  
  692. float rotAngle = 0.0;
  693.  
  694. /*
  695.  * update the scene.  first clear back and z buffers, then draw the
  696.  * cd
  697.  */
  698. void
  699. drawScene()
  700. {
  701.     int i;
  702.  
  703.     glXMakeCurrent(dpy, win, cx);
  704.  
  705.     glClearColor(0.0, 0.0, 0.0, 0.0);
  706.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  707.  
  708.     rotAngle+=15;
  709.  
  710.     if (DO_BACKGROUND) 
  711.         glCallList(BACKGROUND_LIST);
  712.  
  713.     for (i = 0; i < num_cd; i++) {
  714.          glPushMatrix();
  715.            glTranslatef(cd_info[i].posX, cd_info[i].posY, cd_info[i].posZ);
  716.            glRotatef(rotAngle, 1.0, 0.0, 0.0);
  717.            glCallList(CD1_LIST);
  718.          glPopMatrix();
  719.          }
  720.  
  721.  
  722.     glXSwapBuffers(dpy, win);
  723. }
  724.  
  725.  
  726. /*
  727.  * draw a cd.  a cd consists of several disks.  the big one is shiny silver,
  728.  * the others are supposed to be clear plastic, so we will use alpha
  729.  * blending transparency
  730.  */
  731. void
  732. drawCD(GLUquadricObj *cp)
  733. {
  734.  
  735.  if (!cp) {
  736.      cp = gluNewQuadric();
  737.      gluQuadricCallback(cp, GLU_ERROR, gluErrorHandler);
  738.      }
  739.  
  740.  
  741.      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mambient);
  742.      glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mdiffuse);
  743.      glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mspecular);
  744.      glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
  745.  
  746.      gluDisk(cp, 2.0, 5.0, 50.0, 50.0);
  747.  
  748.   /* 
  749.    * enable alpha blending to simulate the clear plastic part
  750.    * of the cd in the center and the outer edge
  751.    */
  752.      glEnable(GL_BLEND);
  753.      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  754.  
  755.      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ma2);
  756.      glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, md2);
  757.      glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, ms2);
  758.  
  759.      gluDisk(cp, 5.0, 5.25, 50.0, 50.0);
  760.      gluDisk(cp, 0.9, 1.75, 50.0, 50.0);
  761.  
  762.      glBlendFunc(GL_ONE, GL_ZERO);
  763.      glDisable(GL_BLEND);
  764.  
  765.  
  766.  
  767.  
  768. }
  769.  
  770. void
  771. gluErrorHandler()
  772. {
  773.  
  774.     fprintf(stderr, "%s\n", gluErrorString(glGetError()));
  775. }
  776.  
  777.  
  778. void
  779. makeCD()
  780. {
  781.  
  782.  
  783.     glNewList(CD1_LIST, GL_COMPILE);
  784.  
  785.        glMaterialfv(GL_FRONT, GL_AMBIENT, gambient);
  786.        glMaterialfv(GL_FRONT, GL_DIFFUSE, gdiffuse);
  787.        glMaterialfv(GL_FRONT, GL_SPECULAR, gspecular);
  788.        glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
  789.  
  790.        drawCD(cp1);
  791.     glEndList();
  792.  
  793. }
  794.  
  795. void
  796. pull()
  797. {
  798.  
  799.  /*
  800.   * start raining cdroms down
  801.   */
  802.  
  803.  
  804.   updateFlightParams();
  805.  
  806. }
  807.  
  808. #include <time.h>
  809.  
  810. void
  811. updateFlightParams()
  812. {
  813.  
  814.    int i;
  815.  
  816.    for (i = 0; i < num_cd; i++) {
  817.  
  818.         if (cd_info[i].state == NONE)
  819.             newParams(i);
  820.  
  821.         if (cd_info[i].posZ <= -85) {
  822.             cd_info[i].state = NONE;
  823.             newParams(i);
  824.             }
  825.  
  826.         cd_info[i].posZ += cd_info[i].ZInc;
  827.         }
  828.  
  829.  
  830.  
  831. }
  832.  
  833.  
  834. /*
  835.  * the checkerboard background
  836.  */
  837. void
  838. drawBackground()
  839. {
  840.  
  841.    float i, j, next;
  842.  
  843.    next = True;
  844.  
  845.  
  846.    glNewList(BACKGROUND_LIST, GL_COMPILE);
  847.  
  848.    glDisable(GL_LIGHTING);
  849.  
  850.    glBegin(GL_QUADS);
  851.  
  852.    for (j = -100; j < 100; j+=10) {
  853.       for (i = -100; i < 100; i+=10) {
  854.  
  855.            if (next) {
  856.                glColor3f(0.31, 0.16, 1.0);
  857.                next = !next;
  858.                }
  859.            else {
  860.                glColor3f(0.15, 0.15, 1.0);
  861.                next = !next;
  862.                }
  863.            
  864.            glVertex3f(i, j, -85.0); 
  865.            glVertex3f(i+10.0, j, -85.0); 
  866.            glVertex3f(i+10.0, j+10.0, -85.0); 
  867.            glVertex3f(i, j+10.0, -85.0); 
  868.  
  869.            }
  870.        next = !next;
  871.  
  872.       }
  873.    glEnd();
  874.   
  875.    glEnable(GL_LIGHTING);
  876.  
  877.    glEndList();
  878.  
  879. }
  880.  
  881. void
  882. initStruct()
  883. {
  884.  
  885.  int i;
  886.  
  887.  for (i = 0; i < MAX_DROPS; i++) {
  888.  
  889.     cd_info[i].state = NONE;
  890.        }
  891.  
  892.  
  893. }
  894.  
  895. void
  896. newParams(int ix)
  897. {
  898.  
  899.    time_t     tloc;
  900.    double     x, y, z;
  901.    long     xt, yt, zt;
  902.  
  903.    static       int firstTime = 0;
  904.  
  905.  
  906.        
  907.        if (!firstTime) {
  908.            time(&tloc);
  909.            srandom((long) tloc);
  910.            firstTime = 1;
  911.            }
  912.  
  913.        x = random();
  914.        y = random();
  915.        z = random();
  916.  
  917.        xt = (x / 100.0);
  918.        xt = xt * 100;
  919.        x = (x - xt)/10;
  920.  
  921.        yt = (y / 100.0);
  922.        yt = yt * 100;
  923.        y = (y - yt)/10;
  924.  
  925.        zt = (z / 100.0);
  926.        zt = zt * 100;
  927.        z = (z - zt)/10;
  928.  
  929.  
  930.  
  931.       cd_info[ix].XInc = x/10;
  932.  
  933.       cd_info[ix].YInc = y/10;
  934.  
  935.       cd_info[ix].ZInc = -z/10;
  936.  
  937.     /*
  938.      * for some variety, if x is od, start at a negative X position
  939.      */
  940.       if ((((int)x) % 2) != 0)
  941.           cd_info[ix].posX = -x;
  942.       else
  943.           cd_info[ix].posX = x;
  944.  
  945.     /*
  946.      * for some variety, if y is even, start at a negative Y position
  947.      */
  948.       if ((((int)y) % 2) != 0)
  949.           cd_info[ix].posY = y;
  950.       else
  951.           cd_info[ix].posY = -y;
  952.  
  953.       cd_info[ix].posZ = 10;
  954.  
  955.       cd_info[ix].state = FALLING;
  956.  
  957. #ifdef DEBUG
  958. fprintf(stderr, "\n new cd[%d] posX: %f  posY: %f  posZ: %f\n",
  959.         ix,cd_info[ix].posX, cd_info[ix].posY,cd_info[ix].posZ);
  960. fprintf(stderr, "\n            XInc: %f  YInc: %f  ZInc: %f\n",
  961.         cd_info[ix].XInc, cd_info[ix].YInc,cd_info[ix].ZInc);
  962. #endif
  963. }
  964.  
  965. void
  966. parseArgs(int argc, char **argv)
  967. {
  968.  
  969.    int i, argOk;
  970.  
  971.    argOk = False;
  972.  
  973.    for (i = 1; i < argc; i++) {
  974.  
  975.         if (strcmp(argv[i], "-nb") == 0) {
  976.             DO_BACKGROUND = False;
  977.             argOk = True;
  978.             }
  979.  
  980.      if (strcmp(argv[i], "-n") == 0)  {
  981.             if (i+1 < argc) {
  982.                 num_cd = atoi(argv[i+1]);
  983.                 i++;
  984.                 }
  985.             else 
  986.                 num_cd = 0;
  987.  
  988.             if ((num_cd > 0) && (num_cd <= MAX_DROPS))
  989.                 argOk = True;
  990.             }
  991.  
  992.  
  993.         if (strcmp(argv[i], "-l") == 0)  {
  994.             if (i+1 < argc) {
  995.                 num_lights = atoi(argv[i+1]);
  996.                 i++;
  997.                 }
  998.             else
  999.                 num_lights = 0;
  1000.  
  1001.             if ((num_lights > 0) && (num_lights <= MAX_LIGHTS))
  1002.                 argOk = True;
  1003.             }
  1004.  
  1005.  
  1006.         if (argOk != True) {
  1007.             fprintf(stderr, 
  1008.                 "\nusage: %s [-nb -n <number of cd's> -l <number of lights>]\n"
  1009.                           , argv[0]);
  1010.             exit(0);
  1011.             }
  1012.    
  1013.         }
  1014. }
  1015.